using System;
using System.Collections.Generic;
using OracleInternal.SqlAndPlsqlParser.LocalParsing;

namespace OracleInternal.SqlAndPlsqlParser.RuleProcessors
{
	internal class OracleMbEarleyRuleMultiProcessorTable
	{
		protected EarleyParserGrammarDefinition m_vEarleyGrammar;

		protected OracleMbEarleyRuleMultiProcessorAddItem[] m_vRuleProcessorItems;

		protected Dictionary<int, List<OracleMbEarleyRuleMultiProcessorToken>> m_vRuleProcessors = new Dictionary<int, List<OracleMbEarleyRuleMultiProcessorToken>>();

		public Dictionary<int, List<OracleMbEarleyRuleMultiProcessorToken>> RuleProcessors => m_vRuleProcessors;

		public OracleMbEarleyRuleMultiProcessorTable(EarleyParserGrammarDefinition grammar, OracleMbEarleyRuleMultiProcessorAddItem[] ruleProcessorItems)
		{
			if (grammar == null || ruleProcessorItems == null)
			{
				throw new ArgumentNullException("The parameters of the processor table constructor cannot be null.");
			}
			m_vEarleyGrammar = grammar;
			m_vRuleProcessorItems = ruleProcessorItems;
			Initialize();
		}

		public virtual void Initialize()
		{
			OracleMbEarleyRuleMultiProcessorAddItem[] vRuleProcessorItems = m_vRuleProcessorItems;
			for (int i = 0; i < vRuleProcessorItems.Length; i++)
			{
				OracleMbEarleyRuleMultiProcessorAddItem oracleMbEarleyRuleMultiProcessorAddItem = vRuleProcessorItems[i];
				AddRuleProcessor(oracleMbEarleyRuleMultiProcessorAddItem.m_vHeadSymbol, oracleMbEarleyRuleMultiProcessorAddItem.m_vRHSSymbols, oracleMbEarleyRuleMultiProcessorAddItem.m_vRuleProcessor, oracleMbEarleyRuleMultiProcessorAddItem.m_vAddType);
			}
		}

		public bool AddRuleProcessor(string headSymbol, string[] rhsSymbols, OracleMbEarleyRuleMultiProcessorDelegate ruleProcessor, OracleMbEarleyRuleMultiProcessorAddType addType)
		{
			if (headSymbol == null)
			{
				throw new OracleLpException(OracleLpExceptionType.RuleMultiProcessor, OracleLpExceptionError.InvalidRuleHeadSymbol, string.Format(OracleLpErrorStrings.GetErrorString(OracleLpExceptionError.InvalidRuleHeadSymbol), headSymbol));
			}
			if (rhsSymbols == null)
			{
				throw new OracleLpException(OracleLpExceptionType.RuleMultiProcessor, OracleLpExceptionError.InvalidRuleRHSSymbols, OracleLpErrorStrings.GetErrorString(OracleLpExceptionError.InvalidRuleRHSSymbols));
			}
			int num = m_vEarleyGrammar.m_vSymbolIndexes[headSymbol];
			if (num == -1)
			{
				throw new OracleLpException(OracleLpExceptionType.RuleMultiProcessor, OracleLpExceptionError.MissingParserSymbol, string.Format(OracleLpErrorStrings.GetErrorString(OracleLpExceptionError.MissingParserSymbol), headSymbol));
			}
			int h = num;
			int num2 = rhsSymbols.Length;
			int[] array = new int[num2];
			for (int i = 0; i < num2; i++)
			{
				string text = rhsSymbols[i];
				if (text == null)
				{
					array[i] = -1;
					continue;
				}
				num = m_vEarleyGrammar.m_vSymbolIndexes[text];
				if (num == -1)
				{
					throw new OracleLpException(OracleLpExceptionType.RuleMultiProcessor, OracleLpExceptionError.MissingParserSymbol, string.Format(OracleLpErrorStrings.GetErrorString(OracleLpExceptionError.MissingParserSymbol), text));
				}
				array[i] = num;
			}
			int num3 = 0;
			ParserRuleTuple[] vBaseSortedRules = m_vEarleyGrammar.m_vBaseSortedRules;
			switch (addType)
			{
			case OracleMbEarleyRuleMultiProcessorAddType.SpecificRule:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, array, m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					throw new OracleLpException(OracleLpExceptionType.RuleMultiProcessor, OracleLpExceptionError.MissingRule, string.Format(OracleLpErrorStrings.GetErrorString(OracleLpExceptionError.MissingRule), parserRuleTuple));
				}
				int key = m_vEarleyGrammar.m_vSortedRulesIndexes[num];
				List<OracleMbEarleyRuleMultiProcessorToken> list;
				if (m_vRuleProcessors.ContainsKey(key))
				{
					list = m_vRuleProcessors[key];
				}
				else
				{
					list = new List<OracleMbEarleyRuleMultiProcessorToken>();
					m_vRuleProcessors[key] = list;
				}
				list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, num2));
				int num4 = num;
				while (num4 > 0)
				{
					num4--;
					if (ParserRuleTupleBaseComparer.s_vInstance.Compare(parserRuleTuple, vBaseSortedRules[num4]) != 0)
					{
						break;
					}
					key = m_vEarleyGrammar.m_vSortedRulesIndexes[num4];
					if (m_vRuleProcessors.ContainsKey(key))
					{
						list = m_vRuleProcessors[key];
					}
					else
					{
						list = new List<OracleMbEarleyRuleMultiProcessorToken>();
						m_vRuleProcessors[key] = list;
					}
					list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, num2));
				}
				int num5 = vBaseSortedRules.Length - 1;
				num4 = num;
				while (num4 < num5)
				{
					num4++;
					if (ParserRuleTupleBaseComparer.s_vInstance.Compare(parserRuleTuple, vBaseSortedRules[num4]) != 0)
					{
						break;
					}
					key = m_vEarleyGrammar.m_vSortedRulesIndexes[num4];
					if (m_vRuleProcessors.ContainsKey(key))
					{
						list = m_vRuleProcessors[key];
					}
					else
					{
						list = new List<OracleMbEarleyRuleMultiProcessorToken>();
						m_vRuleProcessors[key] = list;
					}
					list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, num2));
				}
				break;
			}
			case OracleMbEarleyRuleMultiProcessorAddType.AllMatchingRules:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, new int[0], m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					num = ~num;
				}
				parserRuleTuple = new ParserRuleTuple(h, array, m_vEarleyGrammar);
				for (int i = num; i < vBaseSortedRules.Length && vBaseSortedRules[i].m_vBaseHead == parserRuleTuple.m_vBaseHead; i++)
				{
					int[] vBaseRhs = vBaseSortedRules[i].m_vBaseRhs;
					if (vBaseRhs.Length != num2)
					{
						continue;
					}
					for (num3 = 0; num3 < num2; num3++)
					{
						int num6 = parserRuleTuple.m_vBaseRhs[num3];
						if (num6 != -1 && num6 != vBaseRhs[num3])
						{
							break;
						}
					}
					if (num3 == num2)
					{
						num = m_vEarleyGrammar.m_vSortedRulesIndexes[i];
						List<OracleMbEarleyRuleMultiProcessorToken> list;
						if (m_vRuleProcessors.ContainsKey(num))
						{
							list = m_vRuleProcessors[num];
						}
						else
						{
							list = new List<OracleMbEarleyRuleMultiProcessorToken>();
							m_vRuleProcessors[num] = list;
						}
						list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, num2));
					}
				}
				break;
			}
			case OracleMbEarleyRuleMultiProcessorAddType.AllPartialMatchingRules:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, new int[0], m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					num = ~num;
				}
				parserRuleTuple = new ParserRuleTuple(h, array, m_vEarleyGrammar);
				for (int i = num; i < vBaseSortedRules.Length && vBaseSortedRules[i].m_vBaseHead == parserRuleTuple.m_vBaseHead; i++)
				{
					int[] vBaseRhs = vBaseSortedRules[i].m_vBaseRhs;
					if (vBaseRhs.Length < num2)
					{
						continue;
					}
					int num7 = vBaseRhs.Length - num2;
					for (int j = 0; j <= num7; j++)
					{
						for (num3 = 0; num3 < num2; num3++)
						{
							int num6 = parserRuleTuple.m_vBaseRhs[num3];
							if (num6 != -1 && num6 != vBaseRhs[num3 + j])
							{
								break;
							}
						}
						if (num3 == num2)
						{
							num = m_vEarleyGrammar.m_vSortedRulesIndexes[i];
							List<OracleMbEarleyRuleMultiProcessorToken> list;
							if (m_vRuleProcessors.ContainsKey(num))
							{
								list = m_vRuleProcessors[num];
							}
							else
							{
								list = new List<OracleMbEarleyRuleMultiProcessorToken>();
								m_vRuleProcessors[num] = list;
							}
							list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, j, num2));
							break;
						}
					}
				}
				break;
			}
			case OracleMbEarleyRuleMultiProcessorAddType.AllRulesStartingWith:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, new int[0], m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					num = ~num;
				}
				parserRuleTuple = new ParserRuleTuple(h, array, m_vEarleyGrammar);
				for (int i = num; i < vBaseSortedRules.Length && vBaseSortedRules[i].m_vBaseHead == parserRuleTuple.m_vBaseHead; i++)
				{
					int[] vBaseRhs = vBaseSortedRules[i].m_vBaseRhs;
					if (vBaseRhs.Length < num2)
					{
						continue;
					}
					for (num3 = 0; num3 < num2; num3++)
					{
						int num6 = parserRuleTuple.m_vBaseRhs[num3];
						if (num6 != -1 && num6 != vBaseRhs[num3])
						{
							break;
						}
					}
					if (num3 == num2)
					{
						num = m_vEarleyGrammar.m_vSortedRulesIndexes[i];
						List<OracleMbEarleyRuleMultiProcessorToken> list;
						if (m_vRuleProcessors.ContainsKey(num))
						{
							list = m_vRuleProcessors[num];
						}
						else
						{
							list = new List<OracleMbEarleyRuleMultiProcessorToken>();
							m_vRuleProcessors[num] = list;
						}
						list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, num2));
					}
				}
				break;
			}
			case OracleMbEarleyRuleMultiProcessorAddType.AllRulesEndingWith:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, new int[0], m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					num = ~num;
				}
				parserRuleTuple = new ParserRuleTuple(h, array, m_vEarleyGrammar);
				for (int i = num; i < vBaseSortedRules.Length && vBaseSortedRules[i].m_vBaseHead == parserRuleTuple.m_vBaseHead; i++)
				{
					int[] vBaseRhs = vBaseSortedRules[i].m_vBaseRhs;
					int num5 = vBaseRhs.Length;
					if (num5 < num2)
					{
						continue;
					}
					num5 -= num2;
					for (num3 = 0; num3 < num2; num3++)
					{
						int num6 = parserRuleTuple.m_vBaseRhs[num3];
						if (num6 != -1 && num6 != vBaseRhs[num5 + num3])
						{
							break;
						}
					}
					if (num3 == num2)
					{
						num = m_vEarleyGrammar.m_vSortedRulesIndexes[i];
						List<OracleMbEarleyRuleMultiProcessorToken> list;
						if (m_vRuleProcessors.ContainsKey(num))
						{
							list = m_vRuleProcessors[num];
						}
						else
						{
							list = new List<OracleMbEarleyRuleMultiProcessorToken>();
							m_vRuleProcessors[num] = list;
						}
						list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, num5, num2));
					}
				}
				break;
			}
			default:
			{
				ParserRuleTuple parserRuleTuple = new ParserRuleTuple(h, new int[0], m_vEarleyGrammar);
				num = Array.BinarySearch(vBaseSortedRules, parserRuleTuple, ParserRuleTupleBaseComparer.s_vInstance);
				if (num < 0)
				{
					num = ~num;
				}
				for (int i = num; i < vBaseSortedRules.Length && vBaseSortedRules[i].m_vBaseHead == parserRuleTuple.m_vBaseHead; i++)
				{
					num = m_vEarleyGrammar.m_vSortedRulesIndexes[i];
					List<OracleMbEarleyRuleMultiProcessorToken> list;
					if (m_vRuleProcessors.ContainsKey(num))
					{
						list = m_vRuleProcessors[num];
					}
					else
					{
						list = new List<OracleMbEarleyRuleMultiProcessorToken>();
						m_vRuleProcessors[num] = list;
					}
					list.Add(new OracleMbEarleyRuleMultiProcessorToken(ruleProcessor, 0, -1));
				}
				break;
			}
			}
			return true;
		}
	}
}
